package cn.lbd.lock;

import jdk.internal.org.objectweb.asm.tree.MultiANewArrayInsnNode;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class MyLock implements Watcher {
    private ZooKeeper zooKeeper = null;
    private CountDownLatch countDownLatch = new CountDownLatch(1);
    private String IP = "39.97.191.1:2181";
    private final String LOCK_ROOT_PATH = "/Locks";
    private final String LOCK_NODE_NAME = "/locks_";
    private String lockPath;
    public MyLock() {
        try {
            zooKeeper = new ZooKeeper(IP,5000,this);
            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void process(WatchedEvent event) {
        if (event.getType() == Event.EventType.None) {
            if (event.getState() == Event.KeeperState.SyncConnected) {
                System.out.println("连接成功");
                countDownLatch.countDown();
            }else if (event.getState() == Event.KeeperState.Disconnected) {
                System.out.println("断开连接");
            }else if (event.getState() == Event.KeeperState.Disconnected) {
                System.out.println("会话超时");
                try {
                    zooKeeper = new ZooKeeper(IP,5000,this);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }else if (event.getState() == Event.KeeperState.Disconnected) {
                System.out.println("授权失败");
            }
        }
    }

    public void lock() {
        //创建锁节点
        createLock();
        //尝试获取锁
        attemptLock();
    }

    private void createLock() {
        try {
            if (zooKeeper.exists(LOCK_ROOT_PATH, false) == null) {
                zooKeeper.create(LOCK_ROOT_PATH,new byte[0],ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
            }
            lockPath = zooKeeper.create(LOCK_ROOT_PATH + LOCK_NODE_NAME, new byte[0],
                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL)
                    .substring(LOCK_ROOT_PATH.length() + 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void attemptLock() {
        try {
            List<String> lockList = zooKeeper.getChildren(LOCK_ROOT_PATH, false);
            int index = lockList.indexOf(lockPath);
            if (index == 0) {
                System.out.println("获取到锁 =>" + lockPath);
                return;
            }else {
                String prevList = lockList.get(index - 1);
                //判断前一个锁节点是否还在
                Stat stat = zooKeeper.exists(LOCK_ROOT_PATH + "/" + prevList, watcher);
                if (stat == null) {
                    //不在就尝试去获取
                    attemptLock();
                }else {
                    //在就阻塞等待，直到前个节点移除了再去尝试获取锁
                    synchronized (watcher) {
                        watcher.wait();
                    }
                    attemptLock();
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    Watcher watcher = new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            if (event.getType() == Event.EventType.NodeDeleted) {
                synchronized (this) {
                    //节点被删除就释放锁
                    this.notify();
                }
            }
        }
    };

    public void unlock() {
        try {
            if (zooKeeper != null) {
                zooKeeper.delete(LOCK_ROOT_PATH+"/"+lockPath,-1);
                zooKeeper.close();
                System.out.println("锁已经释放 =>" + LOCK_ROOT_PATH+"/"+lockPath);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
